#include <linux/module.h> //module_init 
#include <linux/printk.h>
#include <linux/cdev.h> //cdev
#include <linux/fs.h> //file_operations
#include <linux/device.h> //class_create
#include <linux/err.h> // -EBUSY
#include <linux/io.h> //ioremap

#include <linux/uaccess.h> //copy_from_user

#include <linux/gpio.h> //gpio

#include <cfg_type.h> //关于硬件平台GPIO定义
#include <linux/miscdevice.h> //misc
//light2---GPIOA28
struct gec6818_light_gpio {
	int gpio;
	char *name;	
};
struct gec6818_light_gpio light_gpio = {PAD_GPIO_D+21,"GPIOD21"};


int gec6818_light_release(struct inode *node, struct file *file)
{
	return 0;
}

int gec6818_light_open(struct inode *node, struct file *file)
{
	
	return 0;
}

//具体实现要根据与应用层之间的通信规约
//当用户按下：发送给用户的状态为1
//当用户未按下：发送给用户的状态为0
//char kbuf[1] :表示按键此时的状态:1或者0;
//该接口的缺点：不能及时把底层的状态发送给用户，所以只能通过上层应用来监控该设备的状态，
//浪费系统资源

ssize_t gec6818_light_read(struct file *file, char __user *user_buff, size_t size, loff_t *offset)
{
	int ret;
	int buf;
	//printk("gec6818_light_read\n");
	//得到light的状态:当用户按下，0，未按下，1
	//int gpio_get_value(unsigned gpio);
	buf = !gpio_get_value(light_gpio.gpio);
	printk("buf = %d\n",buf);

	//通过copy_to_user int copy_to_user(void __user *to, const void *from, int n)
	ret = copy_to_user(user_buff, &buf,size);
    if(ret < 0)
	{
		printk("copy_to_user\n");
		return -EINVAL;
	}
   return size;
}

//[2]
static struct file_operations gec6818_light_ops = {
	.owner = THIS_MODULE,
	.open = gec6818_light_open,
	.read = gec6818_light_read,
	.release = gec6818_light_release,//当应用程序调用close时，执行驱动程序中的接口函数
};

//[1] 定义混杂设备

static struct miscdevice light_misc = {
		.name = "light_drv",  //设备文件的名字
		.fops = &gec6818_light_ops,
		.minor = MISC_DYNAMIC_MINOR, //设置次设备号，MISC_DYNAMIC_MINOR --- 表示由系统动态分配一个次设备号
};
static int __init gec6818light_init(void) //执行insmod执行一次
{
	int ret;
	 // char temp;
	printk("gec6818light_init\n");
	//[3] 注册混杂设备
	 ret = misc_register(&light_misc);
	  if(ret < 0)
	  {
		  printk("misc_register error\n");
		  ret = -EBUSY;
		  goto misc_register_error;
	  }
	  //[5]申请light2对应的GPIO---GPIOA28
		gpio_free(light_gpio.gpio); 

		
	 ret = gpio_request(light_gpio.gpio,light_gpio.name);
	  if(ret < 0)
	  {
		  printk("request  %s error\n",light_gpio.name);
		  ret = -EBUSY;
		  goto gpio_request_error;
		  
	  }  

	  //设置GPIO为输入模式
	  gpio_direction_input(light_gpio.gpio);


	return 0;
	gpio_request_error:
	misc_deregister(&light_misc);
	misc_register_error:
	return ret;
	
}
static void __exit gec6818light_exit(void)
{
	printk("gec6818light_exit\n");
	gpio_free(light_gpio.gpio); 
	//[4] 注销混杂设备
	misc_deregister(&light_misc);
}


module_init(gec6818light_init); //当用户执行insmod beep_drv.ko时，调用module_init，然而，
								  //gec6818beep_init被调用
module_exit(gec6818light_exit); //当用户执行rmmod beep_drv时，调用moudle_exit，

MODULE_AUTHOR("1853.zhang3");
MODULE_DESCRIPTION("GEC6818 light Device Driver");
MODULE_LICENSE("GPL");